The latest version of this notebook is available on https://github.com/qiskit/qiskit-tutorial.
For more information about how to use the IBM Q experience (QX), consult the tutorials, or check out the community.
Pierre Decoodt, Université Libre de Bruxelles
In [1]:
# useful additional packages
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import time
from pprint import pprint
# importing Qiskit
from qiskit import Aer, IBMQ
from qiskit.backends.ibmq import least_busy
from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister, execute
# import basic plot tools
from qiskit.tools.visualization import plot_histogram
In [2]:
IBMQ.load_accounts()
The Monty Hall problem, named after the original host of the television show "Let's Make a Deal" is well known. The game master asks the player to designate between three doors the one behind which a valuable prize has been hidden, such as a luxury car. Goats are hidden behind the other two doors. When the player has issued a preference, the game master opens one of the two remaining doors and one of the goats appears. The player then has the opportunity to choose the closed door remaining instead of the door chosen in first intention.
Is it wise, indifferent or unwise to stick with one's first choice, whatever it may have been? Much has been written on about the optimal strategy because the actual solution is counter-intuitive.
This tutorial is not intended to illustrate one of the many quantum models proposed on this subject and including many variations. It simply describes a model of the original game that can be played many times by players to convince them of the validity of the optimal strategic solution. This kind of simulation was proposed using conventional hardware, like a shell game, a card deck or a programmed pseudo random number generator.
The present game uses the $ |W_{3} \rangle$ creator circuit described in the tutorial "W State 1 : Multi-qubit systems" as a true$^1$ random number generator.
The following state is created and measured: $ |W_{3} \rangle = \frac{1}{\sqrt{3}} \: (|1 0 0 \rangle \: + |0 1 0 \rangle\: + |0 0 1\rangle) $
Each of the three qubits used represents one of the doors. The car is hidden behind the one corresponding to the qubit measured as 1 (excited) during the measurement.
With the help of Hadamard gates, a second true random number generator uses the two-qubit state:
$$ H^{\otimes 2}|0_{a}0_{b}\rangle=|+_{a}\rangle \:|+_{b}\rangle=\frac{|0_{a}\rangle|0_{b}\rangle+|0_{a}\rangle|1_{b}\rangle+|1_{a}\rangle|0_{b}\rangle+|1_{a}\rangle|1_{b}\rangle}{2}$$From the binary value of the measurement $c_{a} c_{b}$, the following quantity represents the result of a coin flipping: $c_{a} \oplus c_{b}$. This two-qubit model of true$^1$ random generator was chosen because bias is minimized on the real device.
This result is used to determine which of the two doors hiding a goat is opened each time the player has chosen the door that hides the car. This phase is obviously not necessary when the player has chosen a door hiding a goat: the game master can not open the door hiding a car, nor the door chosen by the player$^2$.
$^1$ If used on the simulator, it remains a pseudo random number generator.
$^2$ This is a hint for finding the optimal strategy: how many times on average is the game master exempt from tossing a coin?
You may have noticed that the optimal solution has not been hitherto explicitly given. Chances are you already know the answer, and what follows will only comfort you in your belief. For those who are not familiar with this problem, the suspense is preserved and for those who still doubt, this is an opportunity to review your opinion. Play the game a sufficient number of times. Even if you only rely on your intuition for each game, you can use your own success statistics to figure out what is the best strategy.
You will first be asked to choose between the simulator (a good choice to start) or a real device.
In [3]:
"Choice of the backend"
# local qasm simulator
backend = Aer.get_backend('qasm_simulator')
# The flag_qx2 must be "True" for using the ibmqx2.
# "True" is also better when using the simulator
# Use the IBM Quantum Experience
# backend = least_busy(IBMQ.backends(simulator=False))
flag_qx2 = True
if backend == 'ibmqx4':
flag_qx2 = False
print("Your choice for the backend is: ", backend.name(), "flag_qx2 is: ", flag_qx2)
In [4]:
# Here, two useful routine
# Define a F_gate
def F_gate(circ,q,i,j,n,k) :
theta = np.arccos(np.sqrt(1/(n-k+1)))
circ.ry(-theta,q[j])
circ.cz(q[i],q[j])
circ.ry(theta,q[j])
circ.barrier(q[i])
# Define the cxrv gate which uses reverse CNOT instead of CNOT
def cxrv(circ,q,i,j) :
circ.h(q[i])
circ.h(q[j])
circ.cx(q[j],q[i])
circ.h(q[i])
circ.h(q[j])
circ.barrier(q[i],q[j])
In [5]:
# 3-qubit W state
q = QuantumRegister(5)
c = ClassicalRegister(5)
W_states = QuantumCircuit(q,c)
W_states.x(q[2]) #start is |100>
F_gate(W_states,q,2,1,3,1) # Applying F12
F_gate(W_states,q,1,0,3,2) # Applying F23
if flag_qx2 : # option ibmqx2
W_states.cx(q[1],q[2]) # cNOT 21
W_states.cx(q[0],q[1]) # cNOT 32
else : # option ibmqx4
cxrv(W_states,q,1,2)
cxrv(W_states,q,0,1)
# Coin tossing
W_states.h(q[3])
W_states.h(q[4])
for i in range(5) :
W_states.measure(q[i] , c[i])
In [6]:
"Dotted alphabet"
top_bottom = "███████████████"
blank = "█ █"
chosen = []
chosen = chosen + ["███████████████"]
chosen = chosen + ["███████████ ██"]
chosen = chosen + ["██████████ ███"]
chosen = chosen + ["█████████ ████"]
chosen = chosen + ["████████ █████"]
chosen = chosen + ["█ ████ ██████"]
chosen = chosen + ["██ ██ ███████"]
chosen = chosen + ["███ ████████"]
chosen = chosen + ["████ █████████"]
chosen = chosen + ["███████████████"]
here_left = []
here_left = here_left + ["███████████████"]
here_left = here_left + ["███████████████"]
here_left = here_left + ["███ █████████"]
here_left = here_left + ["███ █████████"]
here_left = here_left + ["███ █████████"]
here_left = here_left + ["███ █████████"]
here_left = here_left + ["███ █████████"]
here_left = here_left + ["███ ████"]
here_left = here_left + ["███████████████"]
here_left = here_left + ["███████████████"]
here_center = []
here_center = here_center + ["███████████████"]
here_center = here_center + ["███████████████"]
here_center = here_center + ["█████ ████"]
here_center = here_center + ["███ █████████"]
here_center = here_center + ["███ █████████"]
here_center = here_center + ["███ █████████"]
here_center = here_center + ["███ █████████"]
here_center = here_center + ["█████ ████"]
here_center = here_center + ["███████████████"]
here_center = here_center + ["███████████████"]
here_right = []
here_right = here_right + ["███████████████"]
here_right = here_right + ["███████████████"]
here_right = here_right + ["███ █████"]
here_right = here_right + ["███ ███ ███"]
here_right = here_right + ["███ ███ ███"]
here_right = here_right + ["███ █████"]
here_right = here_right + ["███ ██ ████"]
here_right = here_right + ["███ ███ ███"]
here_right = here_right + ["███████████████"]
here_right = here_right + ["███████████████"]
goa=["█ █","█ ( ) █","█ ( ) █","█ / O O \ █","█ )|( █","█ @ █","█ = █","█ Y █","█ █"]
car=["█ █","█ _______ █","█ / \ █","█ ° _______ ° █","█ / \ █","█ (O) ### (O) █","█ =+=====+= █","█ || || █","█ █"]
In [7]:
"(RE)INITIATES STATISTICS"
nb_randomnb = 0
nb_left = 0
nb_center = 0
nb_right = 0
nb_switches = 0
nb_stays = 0
nb_won_switching = 0
nb_won_sticking = 0
nb_games = 0
n_won = 0
In [9]:
"HERE START THE GAME"
"Hiding the car and the two goats behind the three doors"
Label = ["left", "central", "right"]
shots = 1
repeat = "Y"
while repeat == "Y":
nb_of_cars = 4
while nb_of_cars != 1:
result = execute(W_states, backend=backend, shots=shots)
c5str = str(result.result().get_counts(W_states))
nb_of_cars = int(c5str[4]) + int(c5str[5]) + int(c5str[6])
#this is for checking results from the real computer:
if nb_of_cars == 0:
print("They managed to hide three goats and no car behind the doors! Restarting the hiding process...")
if nb_of_cars >= 2:
print("They managed to hide", nb_of_cars, "cars behind the doors! Restarting the hiding process...")
print(top_bottom," ",top_bottom," ",top_bottom)
for i in range(9):
print(here_left[i]," ",here_center[i]," ",here_right[i])
print(top_bottom," ",top_bottom," ",top_bottom,"\n")
door = input("Game master: Your choice? letter l: left door, c: central door, r: right door + enter\n").upper()
picl = here_left
picc = here_center
picr = here_right
if (door == "L"):
Doorchosen = 1
nb_left = nb_left + 1
picl = chosen
else:
if (door == "C"):
Doorchosen = 2
nb_center = nb_center + 1
picc=chosen
else:
Doorchosen = 3
nb_right = nb_right + 1
picr = chosen
print('Game master: Your choice was the',Label[Doorchosen-1], "door")
"AN OPPORTUNITY TO CHANGE YOUR MIND"
c5str = str(result.result().get_counts(W_states))
randomnb = (int(c5str[2]) + int(c5str[3])) %2
if c5str[4] == "1": #car behind left door
Doorwinning = 1
if Doorchosen == 1:
Dooropen = 2 + randomnb
Doorswitch = 3 - randomnb
if Doorchosen == 2:
Dooropen = 3
Doorswitch = 1
if Doorchosen == 3:
Dooropen = 2
Doorswitch = 1
if c5str[5] == "1": #car behind central door
Doorwinning = 2
if Doorchosen == 2:
Dooropen = 1 + 2*randomnb
Doorswitch = 3 - 2*randomnb
if Doorchosen == 1:
Dooropen = 3
Doorswitch = 2
if Doorchosen == 3:
Dooropen = 1
Doorswitch = 2
if c5str[6] == "1": #car behind right door
Doorwinning = 3
if Doorchosen == 3:
Dooropen = randomnb + 1
Doorswitch = 2 - randomnb
if Doorchosen == 1:
Dooropen = 2
Doorswitch = 3
if Doorchosen == 2:
Dooropen = 1
Doorswitch = 3
if Dooropen == 1:
picl = goa
if Dooropen == 2:
picc = goa
if Dooropen == 3:
picr = goa
print(top_bottom," ",top_bottom," ",top_bottom)
for i in range(9):
print(picl[i]," ",picc[i]," ",picr[i])
print(top_bottom," ",top_bottom," ",top_bottom,"\n")
print('I opened the', Label[Dooropen-1], 'door and you see a goat')
print('You get now an opportunity to change your choice!')
print("Do you want to switch for the ",Label[Doorswitch-1], " door?")
I_switch = input(" Answer by (y/n) + enter\n").upper()
if (I_switch == "Y"):
Doorfinal = Doorswitch
else:
Doorfinal = Doorchosen
"FINAL ANNOUNCE"
if Doorfinal == Doorwinning:
if Doorfinal == 1:
picl = car
if Doorfinal == 2:
picc = car
if Doorfinal == 3:
picr = car
endmessage = 'won the car! Congratulations!'
else:
if Doorfinal == 1:
picl = goa
if Doorfinal == 2:
picc = goa
if Doorfinal == 3:
picr = goa
endmessage = 'won a goat! Sorry!'
print(top_bottom," ",top_bottom," ",top_bottom)
for i in range(9):
print(picl[i]," ",picc[i]," ",picr[i])
print(top_bottom," ",top_bottom," ",top_bottom,"\n")
print('Game master: You opened the',Label[Doorfinal-1],'door and', endmessage)
"STATISTICS"
nb_games = nb_games + 1
nb_randomnb = nb_randomnb + randomnb
if Doorfinal == Doorswitch:
nb_switches = nb_switches +1
if c5str[Doorfinal+3] == "1":
nb_won_switching = nb_won_switching + 1
else:
nb_stays = nb_stays+1
if c5str[Doorfinal+3] == "1":
nb_won_sticking = nb_won_sticking + 1
n_won = nb_won_switching + nb_won_sticking
print()
print("YOUR STATS")
print("nb of games: ", nb_games," total nb won:", n_won, " first choice: left",nb_left," center", nb_center,"right", nb_right)
print("nb sticking: ",nb_stays," nb won when sticking: ",nb_won_sticking,"nb switching:",nb_switches," nb won when switching:",nb_won_switching)
repeat = input("Another game? Answer by (y/n) + enter\n").upper()
print("Game over")
In [ ]: